//
// Created by Administrator on 2021/11/10.
//

#include "ShaderProgram.h"

ShaderProgram::ShaderProgram(
        const std::string& vsPath,
        const std::string& fsPath,
        const std::string& tcsPath,
        const std::string& tesPath,
        const std::string& gsPath)
{
    m_ID = glCreateProgram();
    LoadAndCompileShader(GL_VERTEX_SHADER, vsPath);
    LoadAndCompileShader(GL_FRAGMENT_SHADER, fsPath);
    LoadAndCompileShader(GL_TESS_CONTROL_SHADER, tcsPath);
    LoadAndCompileShader(GL_TESS_EVALUATION_SHADER, tesPath);
    LoadAndCompileShader(GL_GEOMETRY_SHADER, gsPath);
    glLinkProgram(m_ID);
    CheckCompile(m_ID, CompileType::Program);
}

void ShaderProgram::LoadAndCompileShader(GLenum type, const std::string& path) const
{
    if(path.empty())
    {
        return;
    }

    std::string content;
    const GLchar* source;
    GLuint shader;
    LoadFile(path, content);
    source = content.c_str();
    shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, nullptr);
    glCompileShader(shader);
    if(CheckCompile(shader, CompileType::Shader))
    {
        glAttachShader(m_ID, shader);
    }
    glDeleteShader(shader);
}

bool ShaderProgram::CheckCompile(GLuint shader, CompileType type)
{
    char infoLog[2048];
    int success;
    if(type == CompileType::Shader)
    {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
        if(!success)
        {
            glGetShaderInfoLog(shader, 2048, nullptr, infoLog);
        }
    }
    else
    {
        glGetProgramiv(shader, GL_LINK_STATUS, &success);
        if(!success)
        {
            glGetProgramInfoLog(shader, 2048, nullptr, infoLog);
        }
    }
    if(!success)
    {
        ERROR(infoLog);
    }

    return success;
}